home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / NIH Image 1.62b11 / src / Lut.p < prev    next >
Text File  |  1996-08-30  |  54KB  |  2,228 lines

  1. unit Lut;
  2. {This file contains routines that deal with the video Look-Up Table(LUT).}
  3.  
  4. interface
  5.  
  6.     uses
  7.         TYpes, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, Scrap, ToolUtils,
  8.         Resources, Palettes, Printing, ColorPicker, Windows, Files, globals, Utilities, Graphics,
  9.         Dialogs;
  10.  
  11.     function GetPseudoColorIndex: integer;
  12.     function isGrayScaleLUT: boolean;
  13.     procedure DoMouseDownInLUT (event: EventRecord);
  14.     procedure DoCopyColor;
  15.     procedure PasteColor;
  16.     procedure ShowRGBValues (index: integer);
  17.     procedure InvertPalette;
  18.     procedure FindPoints (var x1, y1, x2, y2: integer);
  19.     procedure UpdateMap;
  20.     procedure ResetGraymap;
  21.     procedure DrawMap;
  22.     procedure DoMouseDownInMap;
  23.     procedure EnableThresholding (level: integer);
  24.     procedure DisableThresholding;
  25.     procedure DrawLUT;
  26.     procedure UpdateLUT;
  27.     procedure LoadColorTable (theColorTable: CTabHandle);
  28.     function LoadCLUTResource (id: integer): boolean;
  29.     procedure GetLookupTable (var table: LookupTable);
  30.     procedure RedrawLUTWindow;
  31.     procedure DrawDensitySlice (OptionKey: boolean);
  32.     procedure SelectLutTool;
  33.     procedure EnableDensitySlice;
  34.     procedure SetupPseudocolor;
  35.     procedure DoImportLut (fname: str255; vnum: integer);
  36.     procedure OpenColorTable (fname: str255; RefNum: integer);
  37.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  38.     procedure GetColorTable (id: integer);
  39.     procedure GetLutResource (id: integer);
  40.     procedure DrawScale;
  41.     procedure MakeSpectrum;
  42.     function GetColorTableItem (ctab: ColorTableType): integer;
  43.     procedure SwitchColorTables (item: integer; update: boolean);
  44.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  45.     procedure ResetMap;
  46.     procedure DoLutOptions;
  47.     function SetupMask: boolean;
  48.     procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  49.     procedure ApplyTable (var table: LookupTable);
  50.     procedure FixColors;
  51.  
  52.  
  53.  
  54. implementation
  55.  
  56.  
  57.     function GetPseudoColorIndex: integer;
  58.         var
  59.             index: integer;
  60.     begin
  61.         with info^ do begin
  62.                 index := trunc((nColors) * (ForegroundIndex - ColorStart) / (ColorEnd - ColorStart + 1));
  63.                 if index < 0 then
  64.                     index := 0;
  65.                 if index > (nColors - 1) then
  66.                     index := nColors - 1;
  67.                 GetPseudoColorIndex := index;
  68.             end;
  69.     end;
  70.  
  71.  
  72.     procedure UpdateLUT;
  73.         var
  74.             MaxStart, i, v, index, last: integer;
  75.             inc, sIndex: LongInt;
  76.     begin
  77.         with info^ do begin
  78.                 sIndex := 0;
  79.                 if ColorEnd > ColorStart then
  80.                     inc := nColors * 10000 div (ColorEnd - ColorStart)
  81.                 else
  82.                     inc := 2560000;
  83.                 if ColorStart < 0 then
  84.                     sIndex := -ColorStart * Inc
  85.                 else
  86.                     sIndex := 0;
  87.                 last := nColors - 1;
  88.                 for i := 0 to 255 do
  89.                     with cTable[i].rgb do begin
  90.                             if (i < ColorStart) or (i > ColorEnd) then begin
  91.                                     if i < ColorStart then
  92.                                         cTable[i].rgb := FillColor1
  93.                                     else
  94.                                         cTable[i].rgb := FillColor2;
  95.                                 end
  96.                             else begin
  97.                                     index := sIndex div 10000;
  98.                                     if index > last then
  99.                                         index := last;
  100.                                     Red := bsl(band(RedLUT[index],255), 8);
  101.                                     Green := bsl(band(GreenLUT[index],255), 8);
  102.                                     Blue := bsl(band(BlueLUT[index],255), 8);
  103.                                     sIndex := sIndex + inc;
  104.                                 end;
  105.                         end; {for}
  106.                 if ColorStart = ColorEnd then
  107.                     cTable[ColorStart].rgb := FillColor2
  108.                 else
  109.                     Thresholding := false;
  110.                 LoadLUT(cTable);
  111.                 IdentityFunction := false;
  112.             end;
  113.     end;
  114.  
  115.  
  116.     function GetVLoc: integer;
  117.         var
  118.             loc: point;
  119.             vloc: integer;
  120.     begin
  121.         GetMouse(loc);
  122.         vloc := loc.v;
  123.         if vloc > 255 then
  124.             vloc := 255;
  125.         if vloc <= 0 then
  126.             vloc := 0;
  127.         GetVLoc := vloc;
  128.     end;
  129.  
  130.  
  131.     procedure GetNewColor (var color: RGBColor);
  132.         var
  133.             where: point;
  134.             inRGBColor, OutRGBColor: RGBColor;
  135.     begin
  136.         inRGBColor := color;
  137.         outRGBColor := color;
  138.         where.h := 0;
  139.         where.v := 0;
  140.         InitCursor;
  141.         if GetColor(where, 'Pick a new color...', inRGBColor, outRGBColor) then
  142.             color := outRGBColor;
  143.     end;
  144.  
  145.  
  146.     procedure EditPseudoColors;
  147.         var
  148.             where: point;
  149.             inRGBColor, OutRGBColor: RGBColor;
  150.             index, mloc: integer;
  151.     begin
  152.         SetupLUTUndo;
  153.         with info^ do begin
  154.                 SetPort(LUTWindow);
  155.                 mloc := getvloc;
  156.                 if mloc < ColorStart then begin
  157.                         GetNewColor(FillColor1);
  158.                         UpdateLUT;
  159.                         exit(EditPseudoColors);
  160.                     end;
  161.                 if mloc > ColorEnd then begin
  162.                         GetNewColor(FillColor2);
  163.                         UpdateLUT;
  164.                         exit(EditPseudoColors);
  165.                     end;
  166.                 index := GetPseudoColorIndex;
  167.                 with inRGBColor do begin
  168.                         red := bsl(RedLUT[index], 8);
  169.                         green := bsl(GreenLUT[index], 8);
  170.                         blue := bsl(BlueLUT[index], 8);
  171.                     end;
  172.                 outRGBColor := inRGBColor;
  173.                 where.h := 0;
  174.                 where.v := 0;
  175.                 InitCursor;
  176.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then begin
  177.                         with outRGBColor do begin
  178.                                 RedLUT[index] := bsr(red, 8);
  179.                                 GreenLUT[index] := bsr(green, 8);
  180.                                 BlueLUT[index] := bsr(blue, 8);
  181.                             end;
  182.                         changes := true;
  183.                     end;
  184.                 ColorTable := CustomTable;
  185.                 LutMode := PseudoColor;
  186.                 UpdateLUT;
  187.             end; {with}
  188.     end;
  189.  
  190.  
  191.     function EditSliceColor: boolean;
  192.         var
  193.             where: point;
  194.             inRGBColor, OutRGBColor: RGBColor;
  195.             vloc: integer;
  196.     begin
  197.         SetPort(LUTWindow);
  198.         vloc := getvloc;
  199.         if (vloc >= SliceStart) and (vloc <= SliceEnd) then begin
  200.                 GetNewColor(SliceColor);
  201.                 DrawDensitySlice(false);
  202.                 EditSliceColor := true
  203.             end
  204.         else
  205.             EditSliceColor := false;
  206.     end;
  207.  
  208.  
  209.     procedure ShowLUTValues (tStart, tEnd: integer);
  210.         var
  211.             tPort: GrafPtr;
  212.             value: extended;
  213.             range, NewMin, NewMax: LongInt;
  214.     begin
  215.         with info^ do begin
  216.                 GetPort(tPort);
  217.                 SetPort(InfoWindow);
  218.                 TextSize(9);
  219.                 TextFont(Monaco);
  220.                 TextMode(SrcCopy);
  221.                 MoveTo(xValueLoc, InfoVStart);
  222.                 if DataType <> EightBits then begin
  223.                         range := CurrentMax - CurrentMin;
  224.                         if tEnd < 255 then
  225.                             NewMin := CurrentMin + round(((255 - tEnd) / 255.0) * range)
  226.                         else
  227.                             NewMin := CurrentMin;
  228.                         DrawLong(NewMin);
  229.                         DrawString('    ');
  230.                         MoveTo(xValueLoc, InfoVStart + 10);
  231.                         if tStart > 0 then
  232.                             NewMax := CurrentMax - round((tStart / 255.0) * range)
  233.                         else
  234.                             NewMax := CurrentMax;
  235.                         DrawLong(NewMax);
  236.                         DrawString('    ');
  237.                         SetPort(tPort);
  238.                         exit(ShowLUTValues);
  239.                     end;
  240.                 if fit <> uncalibrated then begin
  241.                         if tStart >= 0 then
  242.                             value := cvalue[tStart]
  243.                         else
  244.                             value := cvalue[0];
  245.                         DrawReal(value, 5, 2);
  246.                         DrawString(' (');
  247.                         DrawReal(tStart, 3, 0);
  248.                         DrawString(')');
  249.                     end
  250.                 else
  251.                     DrawReal(tStart, 3, 0);
  252.                 DrawString('    ');
  253.                 MoveTo(xValueLoc, InfoVStart + 10);
  254.                 if fit <> uncalibrated then begin
  255.                         if tEnd <= 255 then
  256.                             value := cvalue[tEnd]
  257.                         else
  258.                             value := cvalue[255];
  259.                         DrawReal(value, 5, 2);
  260.                         DrawString(' (');
  261.                         DrawReal(tEnd, 3, 0);
  262.                         DrawString(')');
  263.                     end
  264.                 else
  265.                     DrawReal(tEnd, 3, 0);
  266.                 DrawString('    ');
  267.                 SetPort(tPort);
  268.             end;
  269.     end;
  270.  
  271.  
  272.     procedure ShowRGBValues (index: integer);
  273.         var
  274.             tPort: GrafPtr;
  275.             vloc: integer;
  276.     begin
  277.         with info^ do begin
  278.                 GetPort(tPort);
  279.                 SetPort(InfoWindow);
  280.                 TextSize(9);
  281.                 TextFont(Monaco);
  282.                 TextMode(SrcCopy);
  283.                 vloc := InfoVStart;
  284.                 MoveTo(xValueLoc, vloc);
  285.                 DrawLong(index);
  286.                 DrawString('    ');
  287.                 if Info^.fit <> uncalibrated then begin
  288.                         vloc := vloc + 10;
  289.                         MoveTo(xValueLoc, vloc);
  290.                         DrawReal(cvalue[index], 1, precision);
  291.                         DrawString('    ');
  292.                     end;
  293.                 vloc := vloc + 10;
  294.                 MoveTo(xValueLoc, vloc);
  295.                 DrawRGB(index);
  296.                 DrawString('    ');
  297.                 SetPort(tPort);
  298.             end;
  299.     end;
  300.  
  301.  
  302.     procedure FindPoints (var x1, y1, x2, y2: integer);
  303.     begin
  304.         with info^ do begin
  305.                 if ColorStart >= 0 then begin
  306.                         x1 := ColorStart;
  307.                         y1 := 0;
  308.                     end
  309.                 else begin
  310.                         x1 := 0;
  311.                         if ColorEnd > ColorStart then
  312.                             y1 := -ColorStart * 255 div (ColorEnd - ColorStart)
  313.                         else
  314.                             y1 := 0;
  315.                     end;
  316.                 if ColorEnd <= 255 then begin
  317.                         x2 := ColorEnd;
  318.                         y2 := 255;
  319.                     end
  320.                 else begin
  321.                         x2 := 255;
  322.                         if ColorEnd > ColorStart then
  323.                             y2 := 255 * (255 - ColorStart) div (ColorEnd - ColorStart)
  324.                         else
  325.                             y2 := 255;
  326.                     end;
  327.             end;
  328.     end;
  329.  
  330.  
  331.     procedure UpdateMap;
  332.         var
  333.             r: rect;
  334.             x, y, i, h1, h2, h3, v1, v2, v3, dx, dy: integer;
  335.             xcenter, ycenter, brightness, islope, thumb: integer;
  336.             width, max: integer;
  337.             table: LookupTable;
  338.             hrect: rect;
  339.             slope: extended;
  340.             area, value, sum: LongInt;
  341.             p1x, p1y, p2x, p2y: integer;
  342.     begin
  343.         with info^ do begin
  344.                 FindPoints(p1x, p1y, p2x, p2y);
  345.                 SetPort(MapWindow);
  346.                 PenNormal;
  347.                 EraseRect(MapRect2);
  348.                 FrameRect(MapRect1);
  349.                 if LutMode = CustomGrayscale then begin
  350.                         GetLookupTable(table);
  351.                         MoveTo(gmRectLeft, gmRectBottom - 1);
  352.                         for i := 0 to 63 do begin
  353.                                 x := gmRectLeft + i;
  354.                                 y := gmRectBottom - table[i * 4] div 4 - 1;
  355.                                 LineTo(x, y);
  356.                             end;
  357.                         EraseRect(gmSlide1i);
  358.                         EraseRect(gmSlide2i);
  359.                         if ScreenDepth <> 8 then begin
  360.                             DrawLut;
  361.                             UpdatePicWindow;
  362.                         end;
  363.                         exit(UpdateMap);
  364.                     end;
  365.                 h1 := gmRectLeft + p1x div 4;
  366.                 v1 := gmRectBottom - 1 - (p1y div 4);
  367.                 h2 := gmRectLeft + p2x div 4;
  368.                 v2 := gmRectBottom - 1 - (p2y div 4);
  369.                 MoveTo(gmRectLeft, gmRectBottom - 1);
  370.                 LineTo(h1, v1);
  371.                 LineTo(h2, v2);
  372.                 LineTo(gmRectRight - 1, gmRectTop);
  373.                 SetRect(hrect, h1 - 1, v1 - 1, h1 + 2, v1 + 2);
  374.                 PaintRect(hrect); {First handle}
  375.                 SetRect(hrect, h2 - 1, v2 - 1, h2 + 2, v2 + 2);
  376.                 PaintRect(hrect); {Last handle}
  377.                 dx := p2x - p1x;
  378.                 dy := p2y - p1y;
  379.                 xcenter := p1x + dx div 2;
  380.                 ycenter := p1y + dy div 2;
  381.                 h3 := gmRectLeft + xcenter div 4;
  382.                 v3 := gmRectBottom - 1 - (ycenter div 4);
  383.                 SetRect(hrect, h3 - 1, v3 - 1, h3 + 2, v3 + 2);
  384.                 PaintRect(hrect); {Center handle}
  385.                 thumb := gmSlideHeight - 2;
  386.                 max := gmSlideWidth - thumb - 2;
  387.                 width := ColorEnd - ColorStart;
  388.                 brightness := trunc(max * ((ColorStart + width) / (width + 255)));
  389.                 with gmSlide1 do
  390.                     SetRect(hrect, left + brightness + 1, top + 1, left + brightness + thumb + 1, top + thumb + 1);
  391.                 EraseRect(gmSlide1i);
  392.                 PaintRect(hrect);  {Thumb for contrast control}
  393.                 if dx <> 0 then
  394.                     slope := dy / dx
  395.                 else
  396.                     slope := 1000.0;
  397.                 if slope > 1.0 then begin
  398.                         if dy <> 0 then
  399.                             slope := 2.0 - dx / dy
  400.                         else
  401.                             slope := 2.0;
  402.                     end;
  403.                 islope := trunc(slope * 0.5 * (gmSlideWidth - thumb - 2.0));
  404.                 with gmSlide2 do
  405.                     SetRect(hrect, left + islope + 1, top + 1, left + islope + thumb + 1, top + thumb + 1);
  406.                 EraseRect(gmSlide2i);
  407.                 PaintRect(hrect);  {Thumb for contrast control}
  408.                 if ScreenDepth <> 8 then begin
  409.                         if ScreenDepth > 2 then
  410.                             DrawLut;
  411.                         UpdatePicWindow;
  412.                     end;
  413.             end;
  414.     end;
  415.  
  416.  
  417.     procedure UpdateThreshold;
  418.         var
  419.             level: integer;
  420.     begin
  421.         DrawLabels('Thresh:', '', '');
  422.         ShowMessage('');
  423.         with info^ do
  424.             repeat
  425.                 SetPort(LUTWindow);
  426.                 level := GetVLoc;
  427.                 if level <= 255 then begin
  428.                         ColorStart := level;
  429.                         ColorEnd := level;
  430.                         UpdateLUT;
  431.                         UpdateMap;
  432.                     end;
  433.                 Show1Value(level, NoValue);
  434.             until not Button;
  435.     end;
  436.  
  437.  
  438.     procedure UpdateDensitySlice;
  439.         var
  440.             mloc, saveloc, width, delta: integer;
  441.             adjust: (lower, upper, both);
  442.     begin
  443.         DrawLabels('Lower:', 'Upper:', '');
  444.         SetPort(LUTWindow);
  445.         mloc := getvloc;
  446.         saveloc := mloc;
  447.         width := SliceEnd - SliceStart + 1;
  448.         adjust := lower;
  449.         if mloc > (SliceStart + width div 4) then
  450.             adjust := both;
  451.         if mloc > (SliceEnd - width div 4) then
  452.             adjust := upper;
  453.         if (SliceStart = SliceEnd) and (abs(mloc - SliceStart) <= 2) and (SliceStart > 1) and (SliceEnd < 254) then
  454.             adjust := both;
  455.         while button do begin
  456.                 width := SliceEnd - SliceStart + 1;
  457.                 mloc := getvloc;
  458.                 delta := mloc - saveloc;
  459.                 saveloc := mloc;
  460.                 case adjust of
  461.                     lower:  begin
  462.                             SliceStart := mloc;
  463.                             if SliceStart < 1 then
  464.                                 SliceStart := 1;
  465.                             if SliceStart > SliceEnd then
  466.                                 SliceStart := SliceEnd;
  467.                         end;
  468.                     upper:  begin
  469.                             SliceEnd := mloc;
  470.                             if SliceEnd > 254 then
  471.                                 SliceEnd := 254;
  472.                             if SliceEnd < SliceStart then
  473.                                 SliceEnd := SliceStart;
  474.                         end;
  475.                     both:  begin
  476.                             if mloc <= 1 then begin
  477.                                     SliceStart := 1;
  478.                                     SliceEnd := width;
  479.                                 end
  480.                             else if mloc >= 254 then begin
  481.                                     SliceEnd := 254;
  482.                                     SliceStart := 254 - width + 1;
  483.                                 end
  484.                             else if ((SliceStart + delta) >= 1) and ((SliceEnd + delta) <= 254) then begin
  485.                                     SliceStart := SliceStart + delta;
  486.                                     SliceEnd := SliceEnd + delta;
  487.                                 end;
  488.                         end;
  489.                 end; {case}
  490.                 DrawDensitySlice(OptionKeyDown);
  491.                 ShowLUTValues(SliceStart, SliceEnd);
  492.             end; {while}
  493.         DrawDensitySlice(false)
  494.     end;
  495.  
  496.  
  497.     procedure EditExtraColors (entry: integer);
  498.         var
  499.             where: point;
  500.             inRGBColor, OutRGBColor: RGBColor;
  501.     begin
  502.         if (entry <> WhiteIndex) and (entry <> BlackIndex) then begin
  503.                 inRGBColor := ExtraColors[entry];
  504.                 outRGBColor := inRGBColor;
  505.                 where.h := 0;
  506.                 where.v := 0;
  507.                 InitCursor;
  508.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then
  509.                     with info^ do begin
  510.                             ExtraColors[entry] := OutRGBColor;
  511.                             changes := true;
  512.                             LoadLUT(cTable);
  513.                         end
  514.             end
  515.         else
  516.             PutError('Sorry, but you can not edit white or black.');
  517.     end;
  518.  
  519.  
  520.     function GetColorFromLUT (DoubleClick: boolean): integer;
  521.         var
  522.             mloc, color, i: integer;
  523.             loc: point;
  524.     begin
  525.         SetPort(LUTWindow);
  526.         GetMouse(loc);
  527.         if loc.v > 255 then begin
  528.                 color := 0;
  529.                 for i := 1 to nExtraColors + 2 do
  530.                     if PtInRect(loc, ExtraColorsRect[i]) then
  531.                         Color := ExtraColorsEntry[i];
  532.                 if DoubleClick then
  533.                     EditExtraColors(color);
  534.                 GetColorFromLUT := color;
  535.             end
  536.         else
  537.             GetColorFromLUT := loc.v;
  538.     end;
  539.  
  540.  
  541.     function isGrayScaleLUT: boolean;
  542.         var
  543.             i: integer;
  544.             GrayScaleLUT: boolean;
  545.     begin
  546.         with info^ do begin
  547.                 GrayscaleLUT := true;
  548.                 i := 0;
  549.                 repeat
  550.                     with cTable[i].rgb do
  551.                         GrayscaleLUT := GrayscaleLUT and (red = green) and (green = blue);
  552.                     i := i + 1;
  553.                 until (i = 256) or not GrayscaleLUT;
  554.                 isGrayScaleLUT := GrayScaleLUT;
  555.             end;
  556.     end;
  557.  
  558.  
  559.     procedure SetupPseudocolor;
  560.         var
  561.             i: integer;
  562.     begin
  563.         with info^ do begin
  564.                 DisableDensitySlice;
  565.                 Thresholding := false;
  566.                 for i := 1 to 254 do
  567.                     with cTable[i].rgb do begin
  568.                             RedLUT[i] := band(bsr(red, 8), 255);
  569.                             GreenLUT[i] := band(bsr(green, 8), 255);
  570.                             BlueLUT[i] := band(bsr(blue, 8), 255);
  571.                         end;
  572.                 RedLUT[0] := RedLUT[1];
  573.                 GreenLUT[0] := GreenLUT[1];
  574.                 BlueLUT[0] := BlueLUT[1];
  575.                 RedLUT[255] := RedLUT[254];
  576.                 GreenLUT[255] := GreenLUT[254];
  577.                 BlueLUT[255] := BlueLUT[254];
  578.                 nColors := 256;
  579.                 ColorStart := 0;
  580.                 ColorEnd := 255;
  581.                 FillColor1 := ctable[1].rgb;
  582.                 FillColor2 := ctable[254].rgb;
  583.                 InvertedColorTable := false;
  584.             end;
  585.     end;
  586.  
  587.  
  588.     procedure ShowLabels;
  589.     begin
  590.         with info^ do
  591.             if DataType <> EightBits then
  592.                 DrawLabels('Min:', 'Max:', '')
  593.             else
  594.                 DrawLabels('Lower:', 'Upper:', '');
  595.     end;
  596.  
  597.  
  598.     procedure AdjustLUT;
  599.         const
  600.             MinWidth = 8;
  601.         var
  602.             mloc, saveloc, width, delta, cstart, cend: integer;
  603.             adjust: (lower, upper, both);
  604.             loc: point;
  605.     begin
  606.         with info^ do begin
  607.                 SetPort(LUTWindow);
  608.                 SetupLutUndo;
  609.                 ShowLabels;
  610.                 mloc := getvloc;
  611.                 saveloc := mloc;
  612.                 cstart := ColorStart;
  613.                 if cstart < 0 then
  614.                     cstart := 0;
  615.                 cend := ColorEnd;
  616.                 if cend > 255 then
  617.                     cend := 255;
  618.                 width := cend - cstart + 1;
  619.                 adjust := lower;
  620.                 if mloc > (cstart + width div 4) then
  621.                     adjust := both;
  622.                 if mloc > (cend - width div 4) then
  623.                     adjust := upper;
  624.                 while button do begin
  625.                         SetPort(LUTWindow);
  626.                         GetMouse(loc);
  627.                         mloc := loc.v;
  628.                         delta := mloc - saveloc;
  629.                         saveloc := mloc;
  630.                         case adjust of
  631.                             lower:  begin
  632.                                     ColorStart := mloc;
  633.                                     cend := ColorEnd;
  634.                                     if cend > 255 then
  635.                                         cend := 255;
  636.                                     if ColorStart > (cend - MinWidth) then
  637.                                         ColorStart := cend - MinWidth;
  638.                                 end;
  639.                             upper:  begin
  640.                                     ColorEnd := mloc;
  641.                                     cstart := ColorStart;
  642.                                     if cstart < 0 then
  643.                                         cstart := 0;
  644.                                     if ColorEnd < (cstart + MinWidth) then
  645.                                         ColorEnd := cstart + MinWidth;
  646.                                 end;
  647.                             both: 
  648.                                 if (mloc >= 0) and (mloc <= 255) then begin
  649.                                         ColorStart := ColorStart + delta;
  650.                                         ColorEnd := ColorEnd + delta;
  651.                                     end;
  652.                         end;
  653.                         UpdateLUT;
  654.                         UpdateMap;
  655.                         ShowLUTValues(ColorStart, ColorEnd);
  656.                     end;
  657.             end; {with info}
  658.     end;
  659.  
  660.  
  661.     procedure RotateLUT;
  662.         var
  663.             vstart, i, j, delta: integer;
  664.             loc: point;
  665.             tempRed, tempGreen, tempBlue: LutArray;
  666.     begin
  667.         with info^ do begin
  668.             SetPort(LUTWindow);
  669.             GetMouse(loc);
  670.             vstart := loc.v;
  671.             SetupPseudocolor;
  672.             ColorTable := CustomTable;
  673.             repeat
  674.                 GetMouse(loc);
  675.                 delta := vstart - loc.v;
  676.                 for i := 1 to 254 do begin {0 is resevred for white and 255 for black}
  677.                         j := i + delta;
  678.                         if j > 254 then
  679.                             j := j - 254;
  680.                         if j > 254 then
  681.                             j := 254;
  682.                         if j < 1 then
  683.                             j := j + 254;
  684.                         if j < 1 then
  685.                             j := 1;
  686.                         tempRed[i] := RedLut[j];
  687.                         tempGreen[i] := GreenLut[j];
  688.                         tempBlue[i] := BlueLut[j];
  689.                     end;
  690.                 RedLut := tempRed;
  691.                 GreenLut := tempGreen;
  692.                 BlueLut := tempBlue;
  693.                 UpdateLUT;
  694.                 if ScreenDepth <> 8 then begin
  695.                     DrawLut;
  696.                     UpdatePicWindow;
  697.                 end;
  698.                 vstart := loc.v;
  699.             until not button;
  700.         end;
  701.     end;
  702.  
  703.  
  704.     procedure DoMouseDownInLUT (event: EventRecord);
  705.         var
  706.             color: integer;
  707.             DoubleClick: boolean;
  708.     begin
  709.         with info^ do begin
  710.                 if CurrentTool = PickerTool then
  711.                     DoubleClick := (TickCount - LutTime) < GetDblTime
  712.                 else
  713.                     DoubleClick := false;
  714.                 LutTime := TickCount;
  715.                 if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  716.                         color := GetColorFromLUT(DoubleClick);
  717.                         if (CurrentTool = eraser) or OptionKeyDown then
  718.                             SetBackgroundColor(color)
  719.                         else
  720.                             SetForegroundColor(color);
  721.                         if not DoubleClick then
  722.                             exit(DoMouseDownInLUT);
  723.                     end;
  724.                 if Thresholding then begin
  725.                         UpdateThreshold;
  726.                         exit(DoMouseDownInLUT)
  727.                     end;
  728.                 if DoubleClick then begin
  729.                         if DensitySlicing and (CurrentTool = PickerTool) then begin
  730.                                 if EditSliceColor then
  731.                                     exit(DoMouseDownInLUT);
  732.                             end;
  733.                         if CurrentTool = PickerTool then begin
  734.                                 EditPseudoColors;
  735.                                 exit(DoMouseDownInLUT)
  736.                             end;
  737.                     end; {if DoubleClick}
  738.                 if ((CurrentTool = LutTool) or (CurrentTool = Wand)) and DensitySlicing then begin
  739.                         UpdateDensitySlice;
  740.                         exit(DoMouseDownInLUT);
  741.                     end;
  742.                 if OptionKeyDown then
  743.                     RotateLUT
  744.                 else
  745.                     AdjustLUT;
  746.             end; {with}
  747.     end;
  748.  
  749.  
  750.     procedure DoCopyColor;
  751.     begin
  752.         with info^ do begin
  753.                 if ForegroundIndex = WhiteIndex then begin
  754.                         ClipboardColor := WhiteRGB;
  755.                         exit(DoCopyColor);
  756.                     end;
  757.                 if ForegroundIndex = BlackIndex then begin
  758.                         ClipboardColor := BlackRGB;
  759.                         exit(DoCopyColor);
  760.                     end;
  761.                 with cTable[ForegroundIndex].rgb do begin
  762.                         ClipboardColor.red := red;
  763.                         ClipboardColor.green := green;
  764.                         ClipboardColor.blue := blue;
  765.                     end;
  766.                 WhatsOnClip := AColor;
  767.                 ClipTextInBuffer := false;
  768.             end;
  769.     end;
  770.  
  771.  
  772.     procedure PasteColor;
  773.         var
  774.             CurrentColorIndex: integer;
  775.     begin
  776.         with info^ do begin
  777.                 if CurrentTool = PickerTool then begin
  778.                         if ForegroundIndex < ColorStart then begin
  779.                                 FillColor1 := ClipboardColor;
  780.                                 UpdateLUT;
  781.                                 exit(PasteColor);
  782.                             end;
  783.                         if ForegroundIndex > ColorEnd then begin
  784.                                 FillColor2 := ClipboardColor;
  785.                                 UpdateLUT;
  786.                                 exit(PasteColor);
  787.                             end;
  788.                         CurrentColorIndex := GetPseudoColorIndex;
  789.                         with ClipboardColor do begin
  790.                                 RedLUT[CurrentColorIndex] := bsr(red, 8);
  791.                                 GreenLUT[CurrentColorIndex] := bsr(green, 8);
  792.                                 BlueLUT[CurrentColorIndex] := bsr(blue, 8);
  793.                             end;
  794.                         ColorTable := CustomTable;
  795.                         UpdateLUT;
  796.                     end
  797.                 else
  798.                     beep;
  799.             end;
  800.     end;
  801.  
  802.  
  803.     procedure InvertPalette;
  804.         var
  805.             TempRed, TempGreen, TempBlue: LutArray;
  806.             i, LastColor: integer;
  807.             TempTable: MyCSpecArray;
  808.             TempFill: rgbColor;
  809.     begin
  810.         DisableDensitySlice;
  811.         DisableThresholding;
  812.         with info^ do begin
  813.                 TempRed := RedLUT;
  814.                 TempGreen := GreenLUT;
  815.                 TempBlue := BlueLUT;
  816.                 LastColor := ncolors - 1;
  817.                 for i := 0 to LastColor do begin
  818.                         RedLUT[i] := TempRed[LastColor - i];
  819.                         GreenLUT[i] := TempGreen[LastColor - i];
  820.                         BlueLUT[i] := TempBlue[LastColor - i];
  821.                     end;
  822.                 TempFill := FillColor1;
  823.                 FillColor1 := FillColor2;
  824.                 FillColor2 := TempFill;
  825.                 InvertedColorTable := not InvertedColorTable;
  826.                 IdentityFunction := false;
  827.             end;
  828.     end;
  829.  
  830.  
  831.     procedure DrawMap;
  832.         var
  833.             x, y, i: integer;
  834.             table: LookupTable;
  835.     begin
  836.         SetPort(MapWindow);
  837.         PenNormal;
  838.         TextFont(Geneva);
  839.         TextSize(9);
  840.         with gmSlide1 do
  841.             MoveTo(left - 6, bottom);
  842.         DrawChar('B');
  843.         with gmSlide2 do
  844.             MoveTo(left - 6, bottom);
  845.         DrawChar('C');
  846.         FrameRect(gmSlide1);
  847.         FrameRect(gmSlide2);
  848.         FrameRect(gmIcon1);
  849.         FrameRect(gmIcon2);
  850.         with gmIcon1 do begin
  851.                 MoveTo(left, top + 10);
  852.                 LineTo(left + 5, top + 10);
  853.                 LineTo(left + 12, top + 3);
  854.                 LineTo(left + gmIconWidth - 1, top + 3);
  855.             end;
  856.         with gmIcon2 do begin
  857.                 MoveTo(left, top + 10);
  858.                 LineTo(left + gmIconWidth div 2, top + 10);
  859.                 LineTo(left + gmIconWidth div 2, top + 3);
  860.                 LineTo(left + gmIconWidth - 1, top + 3);
  861.             end;
  862.         UpdateMap;
  863.         GrayMapReady := true;
  864.     end;
  865.  
  866.  
  867.     procedure ResetGrayMap;
  868.         var
  869.             i: integer;
  870.     begin
  871.         with info^ do begin
  872.                 DisableDensitySlice;
  873.                 for i := 0 to 255 do begin
  874.                         RedLut[i] := 255 - i;
  875.                         GreenLut[i] := 255 - i;
  876.                         BlueLut[i] := 255 - i;
  877.                     end;
  878.                 FillColor1 := WhiteRGB;
  879.                 FillColor2 := BlackRGB;
  880.                 ColorStart := 0;
  881.                 ColorEnd := 255;
  882.                 nColors := 256;
  883.                 ColorTable := CustomTable;
  884.                 LUTMode := Grayscale;
  885.                 UpdateLUT;
  886.                 if GrayMapReady then
  887.                     UpdateMap;
  888.                 IdentityFunction := true;
  889.                 InvertedColorTable := false;
  890.             end;
  891.     end;
  892.  
  893.  
  894.     procedure AdjustBrightness;
  895.         var
  896.             loc, max, thumb, xcenter, ycenter, width: integer;
  897.             p: point;
  898.     begin
  899.         with info^ do begin
  900.                 thumb := gmSlideHeight - 2;
  901.                 max := gmSlideWidth - thumb - 2;
  902.                 width := ColorEnd - ColorStart;
  903.                 ShowLabels;
  904.                 repeat
  905.                     GetMouse(p);
  906.                     loc := p.h - gmSlide1.left - 2;
  907.                     if loc < 0 then
  908.                         loc := 0;
  909.                     if loc > max then
  910.                         loc := max;
  911.                     ColorStart := -width + round((width + 255) * (loc / max));
  912.                     ColorEnd := ColorStart + width;
  913.                     UpdateLUT;
  914.                     UpdateMap;
  915.                     ShowLUTValues(ColorStart, ColorEnd);
  916.                 until not button;
  917.                 IdentityFunction := false;
  918.             end; {with}
  919.     end;
  920.  
  921.  
  922.     procedure AdjustContrast;
  923.         var
  924.             p: point;
  925.             loc, max, HalfMax, thumb: integer;
  926.             slope, center: extended;
  927.     begin
  928.         with info^ do begin
  929.                 thumb := gmSlideHeight - 2;
  930.                 max := gmSlideWidth - thumb - 2;
  931.                 HalfMax := max div 2;
  932.                 center := ColorStart + (ColorEnd - ColorStart) / 2.0;
  933.                 ShowLabels;
  934.                 repeat
  935.                     GetMouse(p);
  936.                     loc := p.h - gmSlide2.left - 2;
  937.                     if loc < 0 then
  938.                         loc := 0;
  939.                     if loc > max then
  940.                         loc := max;
  941.                     if loc <= HalfMax then
  942.                         slope := loc / HalfMax
  943.                     else if loc < max then
  944.                         slope := HalfMax / (max - loc)
  945.                     else
  946.                         slope := 1000.0;
  947.                     if slope > 0.0 then begin
  948.                             ColorStart := round(center - 127.5 / slope);
  949.                             ColorEnd := round(center + 127.5 / slope);
  950.                         end
  951.                     else begin
  952.                             ColorStart := round(center - MaxColor);
  953.                             ColorEnd := round(center + MaxColor);
  954.                         end;
  955.                     if ColorEnd < 0 then
  956.                         ColorEnd := 0;
  957.                     if ColorStart > 255 then
  958.                         ColorStart := 255;
  959.                     UpdateLUT;
  960.                     UpdateMap;
  961.                     ShowLUTValues(ColorStart, ColorEnd);
  962.                 until not button;
  963.                 IdentityFunction := false;
  964.             end; {with}
  965.     end;
  966.  
  967.  
  968.     procedure ConvertMouseToXY (p: point; var x, y: integer);
  969.     begin
  970.         x := (p.h - gmRectLeft) * 4;
  971.         if x < 0 then
  972.             x := 0;
  973.         if x > 255 then
  974.             x := 255;
  975.         y := (gmRectBottom - p.v) * 4;
  976.         if y < 0 then
  977.             y := 0;
  978.         if y > 255 then
  979.             y := 255;
  980.     end;
  981.  
  982.  
  983.     procedure DoFreehandEditing;
  984.         var
  985.             p: point;
  986.             x1, x2, y, i: integer;
  987.             FirstTime: boolean;
  988.     begin
  989.         with info^ do begin
  990.                 LUTMode := CustomGrayscale;
  991.                 SetPort(MapWindow);
  992.                 FirstTime := true;
  993.                 while button do begin
  994.                         x1 := x2;
  995.                         GetMouse(p);
  996.                         ConvertMouseToXY(p, x2, y);
  997.                         if x2 > 252 then
  998.                             x2 := 252;
  999.                         if FirstTime then begin
  1000.                                 x1 := x2;
  1001.                                 FirstTime := false;
  1002.                             end;
  1003.                         if x2 >= x1 then
  1004.                             for i := x1 to x2 + 3 do
  1005.                                 with cTable[i].rgb do begin
  1006.                                         red := bsl(255 - y, 8);
  1007.                                         green := bsl(255 - y, 8);
  1008.                                         blue := bsl(255 - y, 8);
  1009.                                     end
  1010.                         else
  1011.                             for i := x1 + 3 downto x2 do
  1012.                                 with cTable[i].rgb do begin
  1013.                                         red := bsl(255 - y, 8);
  1014.                                         green := bsl(255 - y, 8);
  1015.                                         blue := bsl(255 - y, 8);
  1016.                                     end;
  1017.                         DrawMap;
  1018.                         LoadLUT(cTable);
  1019.                         if ScreenDepth <> 8 then UpdatePicWindow;
  1020.                     end;
  1021.                 if not isGrayscaleLut then
  1022.                     LutMode := ColorLut;
  1023.             end;
  1024.     end;
  1025.  
  1026.  
  1027.     procedure DisableThresholding;
  1028.     begin
  1029.         with info^ do
  1030.             if thresholding then begin
  1031.                 ColorStart := SaveColorStart;
  1032.                 ColorEnd := SaveColorEnd;
  1033.                 FillColor1 := SaveFill1;
  1034.                 FillColor2 := SaveFill2;
  1035.                 UpdateLut;
  1036.                 UpdateMap;
  1037.                 Thresholding := false;
  1038.             end;
  1039.     end;
  1040.  
  1041.  
  1042.     procedure EnableThresholding (level: integer);
  1043.     begin
  1044.         with info^ do begin
  1045.             if not thresholding then begin
  1046.                 SaveColorStart := ColorStart;
  1047.                 SaveColorEnd := ColorEnd;
  1048.                 SaveFill1 := FillColor1;
  1049.                 SaveFill2 := FillColor2;
  1050.             end;
  1051.             ColorStart := level;
  1052.             ColorEnd := level;
  1053.             FillColor1 := WhiteRGB;
  1054.             FillColor2 := BlackRGB;
  1055.             UpdateLut;
  1056.             UpdateMap;
  1057.             Thresholding := true;
  1058.             if not macro then
  1059.                 SelectLutTool;
  1060.         end;
  1061.     end;
  1062.  
  1063.  
  1064.     procedure ResetMap;
  1065.     begin
  1066.         with info^ do begin
  1067.                 ColorStart := 0;
  1068.                 ColorEnd := 255;
  1069.                 if Thresholding then begin
  1070.                         FillColor1 := SaveFill1;
  1071.                         FillColor2 := SaveFill2;
  1072.                     end;
  1073.                 IdentityFunction := LutMode = Grayscale;
  1074.                 UpdateLUT;
  1075.                 UpdateMap;
  1076.             end;
  1077.     end;
  1078.  
  1079.  
  1080.     procedure DoMouseDownInMap;
  1081.         var
  1082.             r: rect;
  1083.             x, y, p1Dist, p2Dist: integer;
  1084.             mode: (StartPoint, EndPoint, Brightness, AdjustThreshold);
  1085.             p: point;
  1086.             pressed: boolean;
  1087.             x1, y1, x2, y2: integer;
  1088.             xintercept: integer;
  1089.             deltax, deltay, width: LongInt;
  1090.  
  1091.         procedure DoFixup;
  1092.         begin
  1093.             with info^ do
  1094.                 if ((x1 = 0) and (x2 = 0)) or ((x1 = 255) and (x2 = 255)) then begin
  1095.                         y1 := 0;
  1096.                         y2 := 255;
  1097.                     end;
  1098.         end;
  1099.  
  1100.     begin
  1101.         with info^ do begin
  1102.                 DisableDensitySlice;
  1103.                 if OptionKeyDown then begin
  1104.                         DoFreehandEditing;
  1105.                         exit(DoMouseDownInMap);
  1106.                     end;
  1107.                 if LUTMode = CustomGrayscale then
  1108.                     ResetGrayMap;
  1109.                 FindPoints(x1, y1, x2, y2);
  1110.                 SetPort(MapWindow);
  1111.                 GetMouse(p);
  1112.                 if PtInRect(p, gmIcon1) then begin
  1113.                         InvertRect(gmIcon1);
  1114.                         pressed := true;
  1115.                         while Button and pressed do begin
  1116.                                 GetMouse(p);
  1117.                                 if not PtInRect(p, gmIcon1) then begin
  1118.                                         InvertRect(gmIcon1);
  1119.                                         pressed := false;
  1120.                                     end;
  1121.                             end;
  1122.                         repeat
  1123.                         until not button;
  1124.                         if pressed then begin
  1125.                                 InvertRect(gmIcon1);
  1126.                                 ResetMap;
  1127.                                 exit(DoMouseDownInMap)
  1128.                             end;
  1129.                     end;
  1130.                 if PtInRect(p, gmIcon2) then begin
  1131.                         InvertRect(gmIcon2);
  1132.                         pressed := true;
  1133.                         while Button and pressed do begin
  1134.                                 GetMouse(p);
  1135.                                 if not PtInRect(p, gmIcon2) then begin
  1136.                                         InvertRect(gmIcon2);
  1137.                                         pressed := false;
  1138.                                     end;
  1139.                             end;
  1140.                         repeat
  1141.                         until not button;
  1142.                         if pressed then begin
  1143.                                 InvertRect(gmIcon2);
  1144.                                 if Thresholding then
  1145.                                     DisableThresholding
  1146.                                 else
  1147.                                     EnableThresholding(128);
  1148.                                 exit(DoMouseDownInMap)
  1149.                             end;
  1150.                     end;
  1151.                 if PtInRect(p, gmSlide1) then
  1152.                     AdjustBrightness;
  1153.                 if PtInRect(p, gmSlide2) then
  1154.                     AdjustContrast;
  1155.                 if p.v > (gmRectBottom + 4) then begin
  1156.                         if not thresholding and ((x2 - x1) <= 1) then begin
  1157.                                 thresholding := true;
  1158.                                 SaveFill1 := FillColor1;
  1159.                                 SaveFill2 := FillColor2;
  1160.                             end;
  1161.                         exit(DoMouseDownInMap);
  1162.                     end;
  1163.                 if LutMode = CustomGrayscale then
  1164.                     LutMode := Grayscale;
  1165.                 GetMouse(p);
  1166.                 ConvertMouseToXY(p, x, y);
  1167.                 if (x <= 24) or (y <= 32) then
  1168.                     mode := StartPoint
  1169.                 else if (x >= 224) or (y >= 232) then
  1170.                     mode := EndPoint
  1171.                 else if thresholding then
  1172.                     mode := AdjustThreshold
  1173.                 else
  1174.                     mode := brightness;
  1175.                 if mode = AdjustThreshold then
  1176.                     DrawLabels('Thresh:', '', '')
  1177.                 else
  1178.                     ShowLabels;
  1179.                 repeat
  1180.                     case mode of
  1181.                         StartPoint:  begin
  1182.                                 if thresholding then begin
  1183.                                         FillColor1 := SaveFill1;
  1184.                                         FillColor2 := SaveFill2;
  1185.                                     end;
  1186.                                 if x > y then
  1187.                                     y := 0
  1188.                                 else
  1189.                                     x := 0;
  1190.                                 x1 := x;
  1191.                                 if x1 > x2 then
  1192.                                     x2 := x1;
  1193.                                 y1 := y;
  1194.                                 if y1 > y2 then
  1195.                                     y2 := y1;
  1196.                                 DoFixUp;
  1197.                             end;
  1198.                         EndPoint:  begin
  1199.                                 if thresholding then begin
  1200.                                         FillColor1 := SaveFill1;
  1201.                                         FillColor2 := SaveFill2;
  1202.                                     end;
  1203.                                 if x > y then
  1204.                                     x := 255
  1205.                                 else
  1206.                                     y := 255;
  1207.                                 x2 := x;
  1208.                                 if x2 < x1 then
  1209.                                     x1 := x2;
  1210.                                 y2 := y;
  1211.                                 if y2 < y1 then
  1212.                                     y1 := y2;
  1213.                                 DoFixUp;
  1214.                             end;
  1215.                         Brightness:  begin
  1216.                                 deltax := x2 - x1;
  1217.                                 deltay := y2 - y1;
  1218.                                 if deltax = 0 then begin
  1219.                                         x1 := x;
  1220.                                         y1 := 0;
  1221.                                         x2 := x;
  1222.                                         y2 := 255;
  1223.                                     end
  1224.                                 else if deltay = 0 then begin
  1225.                                         x1 := 0;
  1226.                                         y1 := y;
  1227.                                         x2 := 255;
  1228.                                         y2 := y;
  1229.                                     end
  1230.                                 else begin
  1231.                                         x1 := x - y * deltax div deltay;
  1232.                                         xIntercept := x1;
  1233.                                         y1 := 0;
  1234.                                         if x1 < 0 then begin
  1235.                                                 y1 := -deltay * x1 div deltaX;
  1236.                                                 x1 := 0;
  1237.                                             end;
  1238.                                         y2 := 255;
  1239.                                         x2 := 255 * deltax div deltay;
  1240.                                         if xIntercept < 0 then
  1241.                                             x2 := x2 + xIntercept
  1242.                                         else
  1243.                                             x2 := x2 + x1;
  1244.                                         if x2 > 255 then begin
  1245.                                                 y2 := 255 - (x2 - 255) * deltay div deltax;
  1246.                                                 x2 := 255;
  1247.                                             end;
  1248.                                     end;
  1249.                                 if x2 < 1 then
  1250.                                     x2 := 1;
  1251.                                 if y2 < 1 then
  1252.                                     y2 := 1;
  1253.                                 if x1 > 254 then
  1254.                                     x1 := 254;
  1255.                                 if y1 > 254 then
  1256.                                     y1 := 254;
  1257.                             end;
  1258.                         AdjustThreshold:  begin
  1259.                                 x1 := x;
  1260.                                 y1 := 0;
  1261.                                 x2 := x;
  1262.                                 y2 := 255;
  1263.                             end;
  1264.                     end; {case}
  1265. {showmessage(concat(long2str(x1), '  ', long2str(y1), '  ', long2str(x2), '  ', long2str(y2), crStr, long2str(ColorStart), '  ', long2str(ColorEnd)));}
  1266.                     width := x2 - x1;
  1267.                     if y1 = 0 then
  1268.                         ColorStart := x1
  1269.                     else begin
  1270.                             if (y2 > y1) then
  1271.                                 ColorStart := -width * y1 div (y2 - y1)
  1272.                             else
  1273.                                 ColorStart := -MaxColor;
  1274.                         end;
  1275.                     if y2 = 255 then
  1276.                         ColorEnd := x2
  1277.                     else begin
  1278.                             if (y2 > y1) then
  1279.                                 ColorEnd := 255 + width * (255 - y2) div ((y2 - y1))
  1280.                             else
  1281.                                 ColorEnd := MaxColor;
  1282.                         end;
  1283.                     UpdateLUT;
  1284.                     UpdateMap;
  1285.                     if thresholding then
  1286.                         Show1Value(ColorStart, NoValue)
  1287.                     else
  1288.                         ShowLUTValues(ColorStart, ColorEnd);
  1289.                     GetMouse(p);
  1290.                     ConvertMouseToXY(p, x, y);
  1291.                 until not Button;
  1292.                 IdentityFunction := false;
  1293.                 if not thresholding and ((x2 - x1) <= 1) then begin
  1294.                         thresholding := true;
  1295.                         SaveFill1 := FillColor1;
  1296.                         SaveFill2 := FillColor2;
  1297.                     end;
  1298.             end; {with info}
  1299.     end;
  1300.  
  1301.  
  1302.     procedure DrawLUT;
  1303.         var
  1304.             tPort: GrafPtr;
  1305.             h, v, i: integer;
  1306.     begin
  1307.         GetPort(tPort);
  1308.         SetPort(LUTWindow);
  1309.         with LutWindow^ do begin
  1310.                 for v := 0 to 255 do begin
  1311.                         SetFColor(v);
  1312.                         MoveTo(0, v);
  1313.                         LineTo(cwidth, v)
  1314.                     end;
  1315.                 for i := 1 to nExtraColors + 2 do begin
  1316.                         SetFColor(ExtraColorsEntry[i]);
  1317.                         PaintRect(ExtraColorsRect[i]);
  1318.                     end;
  1319.                 TextFont(Geneva);
  1320.                 TextSize(9);
  1321.                 with ExtraColorsRect[1] do
  1322.                     MoveTo(left + 3, bottom - 1);
  1323.                 SetFColor(BlackIndex);
  1324.                 DrawString('white');
  1325.                 with ExtraColorsRect[2] do
  1326.                     MoveTo(left + 4, bottom - 1);
  1327.                 InvertRect(ExtraColorsRect[2]);
  1328.                 DrawString('black');
  1329.                 InvertRect(ExtraColorsRect[2]);
  1330.             end;
  1331.         SetPort(tPort);
  1332.     end;
  1333.  
  1334.  
  1335.     function LoadPP2Palette: boolean;
  1336. {Loads COLR resource from PixelPaint 2.0 palette file.}
  1337.         var
  1338.             i: integer;
  1339.             size: LongInt;
  1340.             h: Handle;
  1341.             PPColorTable: record
  1342.                     ctSize: INTEGER;
  1343.                     table: array[0..255] of RGBColor;
  1344.                 end;
  1345.     begin
  1346.         h := GetResource('COLR', 999);
  1347.         size := GetHandleSize(handle(h));
  1348.         if (ResError = NoErr) and (size = 1538) then
  1349.             with info^ do begin
  1350.                     BlockMove(handle(h)^, @PPColorTable, SizeOf(PPColorTable));
  1351.                     with PPColorTable do begin
  1352.                             for i := 0 to 255 do
  1353.                                 cTable[i].rgb := table[i];
  1354.                         end;
  1355.                     LoadLUT(cTable);
  1356.                     LutMode := ColorLut;
  1357.                     SetupPseudocolor;
  1358.                     IdentityFunction := false;
  1359.                     LoadPP2Palette := true;
  1360.                 end
  1361.         else
  1362.             LoadPP2Palette := false;
  1363.         if h <> nil then
  1364.             DisposeHandle(h);
  1365.     end;
  1366.  
  1367.  
  1368.     procedure LoadColorTable (theColorTable: CTabHandle);
  1369.         const
  1370.             ExpectedSize = 2056;
  1371.         var
  1372.             size: LongInt;
  1373.             MyColorTable: record
  1374.                     ctSeed: LONGINT;
  1375.                     transIndex: INTEGER;
  1376.                     ctSize: INTEGER;
  1377.                     ctTable: MyCSpecArray;
  1378.                 end;
  1379.     begin
  1380.         size := GetHandleSize(handle(theColorTable));
  1381.         if size < ExpectedSize then
  1382.             exit(LoadColorTable);
  1383.         if size > ExpectedSize then
  1384.             Size := ExpectedSize;
  1385.         BlockMove(handle(theColorTable)^, @MyColorTable, size);
  1386.         LoadLUT(MyColorTable.ctTable);
  1387.         with info^ do begin
  1388.                 cTable := MyColorTable.ctTable;
  1389.                 LutMode := ColorLut;
  1390.                 IdentityFunction := false;
  1391.             end;
  1392.         SetupPseudocolor;
  1393.     end;
  1394.  
  1395.  
  1396.     function LoadCLUTResource;{(id:integer):boolean}
  1397.         const
  1398.             ExpectedSize = 2056;
  1399.         var
  1400.             Size: LongInt;
  1401.             h: cTabHandle;
  1402.     begin
  1403.         DisableDensitySlice;
  1404.         h := GetCTable(id);
  1405.         size := GetHandleSize(handle(h));
  1406.         if (ResError <> NoErr) or (size < ExpectedSize) then begin
  1407.                 LoadCLUTResource := false;
  1408.                 if id = PixelpaintID then begin
  1409.                         if LoadPP2Palette then
  1410.                             LoadCLUTResource := true;
  1411.                     end;
  1412.                 if h <> nil then
  1413.                     DisposeCTable(h);
  1414.                 exit(LoadCLUTResource)
  1415.             end;
  1416.         LoadColorTable(h);
  1417.         DisposeCTable(h);
  1418.         LoadCLUTResource := true;
  1419.     end;
  1420.  
  1421.  
  1422.     procedure GetLookupTable;{(VAR table:LookupTable)}
  1423.         var
  1424.             i, r, g, b: integer;
  1425.             GrayscaleImage: boolean;
  1426.     begin
  1427.         with info^ do begin
  1428.                 if DensitySlicing then begin
  1429.                         for i := 0 to 255 do
  1430.                             if (i >= SliceStart) and (i <= SliceEnd) then begin
  1431.                                     if ThresholdToForeground then
  1432.                                         table[i] := ForegroundIndex
  1433.                                     else
  1434.                                         table[i] := i
  1435.                                 end
  1436.                             else begin
  1437.                                     if NonThresholdToBackground then
  1438.                                         table[i] := BackgroundIndex
  1439.                                     else
  1440.                                         table[i] := i
  1441.                                 end;
  1442.                         DisableDensitySlice;
  1443.                         exit(GetLookupTable);
  1444.                     end;
  1445.                 if (LutMode = GrayScale) or (LutMode = CustomGrayscale) then
  1446.                     for i := 0 to 255 do
  1447.                         table[i] := 255 - BSR(cTable[i].RGB.red, 8)
  1448.                 else begin
  1449.                         table[0] := 0;
  1450.                         for i := 1 to 254 do
  1451.                             with cTable[i].RGB do
  1452.                                 table[i] := 255 - trunc(band(bsr(red, 8), 255) * 0.3 + band(bsr(green, 8), 255) * 0.59 + band(bsr(blue, 8), 255) * 0.11);
  1453.                         table[255] := 255;
  1454.                     end;
  1455.             end; {with}
  1456.     end;
  1457.  
  1458.  
  1459.     procedure RedrawLUTWindow;
  1460.     begin
  1461.         LoadLUT(info^.cTable);
  1462.         cheight := 256 + (2 + nExtraColors) * ExtraColorsHeight;
  1463.         SizeWindow(LUTWindow, cwidth, cheight, true);
  1464.         if ScreenDepth <> 8 then
  1465.             DrawLUT;
  1466.     end;
  1467.  
  1468.  
  1469.     procedure DrawDensitySlice (OptionKey: boolean);
  1470.         var
  1471.             i, tRed: integer;
  1472.     begin
  1473.         with info^ do begin
  1474.                 if OptionKey then begin
  1475.                         UndoLutChange;
  1476.                         if ScreenDepth <> 8 then begin
  1477.                             DrawLut;
  1478.                             UpdatePicWindow;
  1479.                         end;
  1480.                         exit(DrawDensitySlice);
  1481.                     end
  1482.                 else
  1483.                     for i := 0 to 255 do
  1484.                         if (i >= SliceStart) and (i <= SliceEnd) then
  1485.                             cTable[i].rgb := SliceColor
  1486.                         else
  1487.                             ctable[i].rgb := UndoInfo^.cTable[i].rgb;
  1488.                 LoadLUT(cTable);
  1489.                 if ScreenDepth <> 8 then begin
  1490.                         if ScreenDepth > 2 then
  1491.                             DrawLut;
  1492.                         UpdatePicWindow;
  1493.                     end;
  1494.             end;
  1495.     end;
  1496.  
  1497.  
  1498.     procedure SelectLutTool;
  1499.         var
  1500.             tPort: GrafPtr;
  1501.     begin
  1502.         if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  1503.                 GetPort(tPort);
  1504.                 SetPort(ToolWindow);
  1505.                 InvalRect(ToolRect[CurrentTool]);
  1506.                 InvalRect(ToolRect[LutTool]);
  1507.                 CurrentTool := LutTool;
  1508.                 isSelectionTool := false;
  1509.                 SetPort(tPort);
  1510.             end;
  1511.     end;
  1512.  
  1513.  
  1514.     procedure EnableDensitySlice;
  1515.     begin
  1516.         if not DensitySlicing then begin
  1517.                 SetupLutUndo;
  1518.                 DrawDensitySlice(false);
  1519.                 DensitySlicing := true;
  1520.                 SelectLUTTool;
  1521.             end;
  1522.     end;
  1523.  
  1524.  
  1525.     procedure DoImportLut (fname: str255; vnum: integer);
  1526.         var
  1527.             err: OSErr;
  1528.             f, i,j,tRed: integer;
  1529.             ByteCount: LongInt;
  1530.             ImportedLUT: array[1..3] of packed array[0..255] of byte;
  1531.     begin
  1532.         DisableDensitySlice;
  1533.         err := fsopen(fname, vNum, f);
  1534.         ByteCount := 768;
  1535.         err := fsRead(f, ByteCount, @ImportedLUT);
  1536.         if err = NoErr then
  1537.             with info^ do begin
  1538.                     for i := 0 to 255 do
  1539.                         with cTable[i], cTable[i].rgb do begin
  1540.                                 value := 0;
  1541.                                 red := bsl(band(ImportedLUT[1, i],255), 8);
  1542.                                 green := bsl(band(ImportedLUT[2, i],255), 8);
  1543.                                 blue := bsl(band(ImportedLUT[3, i],255), 8);
  1544.                             end;
  1545.                     LoadLUT(cTable);
  1546.                     SetupPseudocolor;
  1547.                     LutMode := PseudoColor;
  1548.                     IdentityFunction := false;
  1549.                     if isGrayScaleLUT then
  1550.                         info^.LutMode := CustomGrayScale;
  1551.                     UpdateLut;
  1552.                     UpdateMap;
  1553.                 end
  1554.         else
  1555.             beep;
  1556.         err := fsClose(f);
  1557.     end;
  1558.  
  1559.  
  1560.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  1561. {Opens palette files created by versions NIH Image earlier than 1.42.}
  1562.         var
  1563.             PaletteHeader: ColorArray;
  1564.             err, f, ColorWidth: integer;
  1565.             size: LongInt;
  1566.     begin
  1567.         DisableDensitySlice;
  1568.         err := fsopen(fname, RefNum, f);
  1569.         with info^ do begin
  1570.                 size := SizeOf(ColorArray);
  1571.                 err := fsread(f, size, @PaletteHeader);
  1572.                 nColors := PaletteHeader[0];
  1573.                 if nColors > MaxPseudocolors then
  1574.                     nColors := MaxPseudoColors;
  1575.                 ColorEnd := 255 - PaletteHeader[1];
  1576.                 ColorWidth := PaletteHeader[2];
  1577.                 ColorStart := ColorEnd - nColors * ColorWidth + 1;
  1578.                 if ColorStart < 0 then
  1579.                     ColorStart := 0;
  1580.                 FillColor1 := BlackRGB;
  1581.                 FillColor2 := BlackRGB;
  1582.                 err := fsread(f, size, @RedLut);
  1583.                 err := fsread(f, size, @GreenLut);
  1584.                 err := fsread(f, size, @BlueLut);
  1585.                 LutMode := PseudoColor;
  1586.                 InvertedColorTable := false;
  1587.             end;
  1588.         err := fsclose(f);
  1589.     end;
  1590.  
  1591.  
  1592.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  1593. {Opens palette files created by versions of NIH Image later than 1.41.}
  1594.         var
  1595.             err, f: integer;
  1596.             count: LongInt;
  1597.             hdr: PaletteHeader;
  1598.     begin
  1599.         DisableDensitySlice;
  1600.         err := fsopen(fname, RefNum, f);
  1601.         with info^ do begin
  1602.                 count := SizeOf(PaletteHeader);
  1603.                 err := fsread(f, count, @hdr);
  1604.                 with hdr do begin
  1605.                         nColors := pnColors;
  1606.                         if nColors > 256 then
  1607.                             nColors := 256;
  1608.                         ColorStart := pColorStart;
  1609.                         ColorEnd := pColorEnd;
  1610.                         FillColor1 := pFill1;
  1611.                         FillColor2 := pFill2;
  1612.                         InvertedColorTable := false;
  1613.                     end;
  1614.                 count := nColors;
  1615.                 err := fsread(f, count, @RedLut);
  1616.                 count := nColors;
  1617.                 err := fsread(f, count, @GreenLut);
  1618.                 count := nColors;
  1619.                 err := fsread(f, count, @BlueLut);
  1620.                 LutMode := PseudoColor;
  1621.             end;
  1622.         err := fsclose(f);
  1623.     end;
  1624.  
  1625.  
  1626.     procedure OpenColorTable (fname: str255; RefNum: integer);
  1627.         var
  1628.             err: OSErr;
  1629.             f: integer;
  1630.             FileSize, count: LongInt;
  1631.             id: packed array[1..4] of char;
  1632.     begin
  1633.         err := fsopen(fname, RefNum, f);
  1634.         err := GetEOF(f, FileSize);
  1635.         count := SizeOf(id);
  1636.         err := fsread(f, count, @id);
  1637.         err := fsclose(f);
  1638.         if FileSize = 768 then
  1639.             DoImportLut(fname, RefNum)
  1640.         else if id = 'ICOL' then
  1641.             OpenNewPalette(fname, RefNum)
  1642.         else
  1643.             OpenOldPalette(fname, RefNum);
  1644.         UpdateLUT;
  1645.         UpdateMap;
  1646.     end;
  1647.  
  1648.  
  1649.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  1650.         var
  1651.             RefNum: integer;
  1652.             ok: boolean;
  1653.             err: OSErr;
  1654.     begin
  1655.         err := SetVol(nil, vnum);
  1656.         refNum := OpenResFile(fname);
  1657.         if RefNum <> -1 then begin
  1658.                 if FileType = 'CLUT' then
  1659.                     ok := LoadClutResource(KlutzID)
  1660.                 else
  1661.                     ok := LoadClutResource(PixelPaintID); {Load PixelPaint or Canvas palette}
  1662.                 CloseResFile(RefNum);
  1663.                 if isGrayScaleLUT then begin
  1664.                         info^.LutMode := CustomGrayScale;
  1665.                         DrawMap;
  1666.                     end;
  1667.             end;
  1668.     end;
  1669.  
  1670.  
  1671.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  1672.         var
  1673.             i: integer;
  1674.     begin
  1675.         with hdr, info^ do begin
  1676.                 pID := 'ICOL';
  1677.                 pVersion := version;
  1678.                 pnColors := nColors;
  1679.                 pColorStart := ColorStart;
  1680.                 pColorEnd := ColorEnd;
  1681.                 pFill1 := FillColor1;
  1682.                 pFill2 := FillColor2;
  1683.                 for i := 1 to 4 do
  1684.                     pUnused[i] := 0;
  1685.             end;
  1686.     end;
  1687.  
  1688.  
  1689.     procedure SaveLutResource;
  1690. {Saves the current color table as  a CPAL resource}
  1691.         var
  1692.             id: integer;
  1693.             canceled: boolean;
  1694.             PalH: handle;
  1695.             hdr: PaletteHeader;
  1696.             p: ptr;
  1697.     begin
  1698.         with info^ do begin
  1699.                 id := GetInt('Resource ID', 1000, canceled);
  1700.                 if canceled then
  1701.                     exit(SaveLutResource);
  1702.                 PalH := GetResource('CPAL', id);
  1703.                 if GetHandleSize(PalH) > 0 then begin
  1704.                         RemoveResource(PalH);
  1705.                         DisposeHandle(PalH);
  1706.                     end;
  1707.                 InitPaletteHeader(hdr);
  1708.                 PalH := NewHandle(SizeOF(PaletteHeader) + nColors * 3);
  1709.                 p := PalH^;
  1710.                 BlockMove(@hdr, p, SizeOf(PaletteHeader));
  1711.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1712.                 BlockMove(@RedLut, p, nColors);
  1713.                 p := ptr(ord4(p) + nColors);
  1714.                 BlockMove(@GreenLut, p, nColors);
  1715.                 p := ptr(ord4(p) + nColors);
  1716.                 BlockMove(@BlueLut, p, nColors);
  1717.                 AddResource(PalH, 'CPAL', id, '');
  1718.                 WriteResource(PalH);
  1719.                 if ResError <> NoErr then
  1720.                     beep;
  1721.                 DisposeHandle(PalH);
  1722.             end;
  1723.     end;
  1724.  
  1725.  
  1726.     procedure GetLutResource (id: integer);
  1727.         var
  1728.             LutH: handle;
  1729.             hdr: PaletteHEader;
  1730.             p: ptr;
  1731.     begin
  1732.         with info^ do begin
  1733.                 LutH := GetResource('CPAL', id);
  1734.                 if (ResError <> noErr) or (LutH = nil) then begin
  1735.                         beep;
  1736.                         if LutH <> nil then
  1737.                             ReleaseResource(LutH);
  1738.                         exit(GetLutResource)
  1739.                     end;
  1740.                 p := LutH^;
  1741.                 BlockMove(p, @hdr, SizeOf(PaletteHeader));
  1742.                 with hdr do begin
  1743.                         if pID <> 'ICOL' then begin
  1744.                                 beep;
  1745.                                 ReleaseResource(LutH);
  1746.                                 exit(GetLutResource);
  1747.                             end;
  1748.                         nColors := pnColors;
  1749.                         if nColors > 256 then
  1750.                             nColors := 256;
  1751.                         ColorStart := pColorStart;
  1752.                         ColorEnd := pColorEnd;
  1753.                         FillColor1 := pFill1;
  1754.                         FillColor2 := pFill2;
  1755.                         InvertedColorTable := false;
  1756.                     end;
  1757.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1758.                 BlockMove(p, @RedLut, nColors);
  1759.                 p := ptr(ord4(p) + nColors);
  1760.                 BlockMove(p, @GreenLut, nColors);
  1761.                 p := ptr(ord4(p) + nColors);
  1762.                 BlockMove(p, @BlueLut, nColors);
  1763.                 ReleaseResource(LutH);
  1764.             end;
  1765.     end;
  1766.  
  1767.  
  1768.     procedure DrawScale;
  1769.         var
  1770.             hloc, vloc, width, height, SaveForeground, LUTStart, LutEnd, LUTWidth: integer;
  1771.             SaveGDevice: GDHandle;
  1772.     begin
  1773.         if NoSelection or NotRectangular then
  1774.             exit(DrawScale);
  1775.         ShowWatch;
  1776.         with info^.RoiRect, info^ do begin
  1777.                 width := right - left;
  1778.                 height := bottom - top;
  1779.                 if (width = 0) or (height = 0) then
  1780.                     exit(DrawScale);
  1781.                 SaveGDevice := GetGDevice;
  1782.                 SetGDevice(osGDevice);
  1783.                 SetPort(GrafPtr(osPort));
  1784.                 PenNormal;
  1785.                 SetupUndoFromClip;
  1786.                 SetupUndo;
  1787.                 WhatToUndo := UndoEdit;
  1788.                 SaveForeground := ForegroundIndex;
  1789.                 LUTStart := ColorStart;
  1790.                 if LutStart <= 0 then
  1791.                     LutStart := 1;
  1792.                 LutEnd := ColorEnd;
  1793.                 if LutEnd >= 255 then
  1794.                     LutEnd := 254;
  1795.                 LUTWidth := LutEnd - LutStart + 1;
  1796.                 if width >= height then
  1797.                     for hloc := left to right - 1 do begin
  1798.                             SetForegroundColor(trunc(((hloc - left) / width) * LUTWidth) + LUTStart);
  1799.                             MoveTo(hloc, top);
  1800.                             LineTo(hloc, Bottom - 1);
  1801.                         end
  1802.                 else
  1803.                     for vloc := top to bottom - 1 do begin
  1804.                             SetForegroundColor(trunc(((vloc - top) / height) * LUTWidth) + LUTStart);
  1805.                             MoveTo(left, vloc);
  1806.                             LineTo(right - 1, vloc);
  1807.                         end;
  1808.                 SetForegroundColor(SaveForeground);
  1809.                 changes := true;
  1810.             end;
  1811.         SetupRoiRect;
  1812.         SetGDevice(SaveGDevice);
  1813.     end;
  1814.  
  1815.  
  1816.     procedure MakeSpectrum;
  1817.   {Generates the "Spectrum" color table.}
  1818.         const
  1819.             Sat = -1;
  1820.             Val = -1;
  1821.         var
  1822.             i: integer;
  1823.             color: HSVColor;
  1824.     begin
  1825.         with info^ do begin
  1826.                 for i := 0 to 255 do begin
  1827.                         color.hue := i * 256;
  1828.                         color.saturation := sat;
  1829.                         color.value := val;
  1830.                         HSV2RGB(color, ctable[i].rgb);
  1831.                     end;
  1832.                 LutMode := ColorLut;
  1833.                 IdentityFunction := false;
  1834.                 SetupPseudocolor;
  1835.             end;
  1836.     end;
  1837.  
  1838.  
  1839.     function GetColorTableItem (ctab: ColorTableType): integer;
  1840.     begin
  1841.         case ctab of
  1842.             AppleDefault: 
  1843.                 GetColorTableItem := SystemPaletteItem;
  1844.             Pseudo20: 
  1845.                 GetColorTableItem := Pseudo20Item;
  1846.             Pseudo32: 
  1847.                 GetColorTableItem := Pseudo32Item;
  1848.             Rainbow: 
  1849.                 GetColorTableItem := RainbowItem;
  1850.             Fire1: 
  1851.                 GetColorTableItem := Fire1Item;
  1852.             Fire2: 
  1853.                 GetColorTableItem := Fire2Item;
  1854.             Ice: 
  1855.                 GetColorTableItem := IceItem;
  1856.             Grays: 
  1857.                 GetColorTableItem := GraysItem;
  1858.             Spectrum: 
  1859.                 GetColorTableItem := SpectrumItem;
  1860.             otherwise
  1861.                 GetColorTableItem := Pseudo20Item;
  1862.         end;
  1863.     end;
  1864.  
  1865.  
  1866.     procedure SwitchColorTables (item: integer; update: boolean);
  1867.         var
  1868.             ok: boolean;
  1869.     begin
  1870.         DisableDensitySlice;
  1871.         if update then
  1872.             SetupLutUndo;
  1873.         with info^ do begin
  1874.                 case item of
  1875.                     SystemPaletteItem:  begin
  1876.                             ok := LoadCLUTResource(AppleDefaultCLUT);
  1877.                             ColorTable := AppleDefault;
  1878.                         end;
  1879.                     Pseudo20Item:  begin
  1880.                             GetLutResource(Pseudo20ID);
  1881.                             ColorTable := Pseudo20;
  1882.                         end;
  1883.                     Pseudo32Item:  begin
  1884.                             GetLutResource(Pseudo32ID);
  1885.                             ColorTable := Pseudo32;
  1886.                         end;
  1887.                     RainbowItem:  begin
  1888.                             GetLutResource(RainbowID);
  1889.                             ColorTable := Rainbow;
  1890.                         end;
  1891.                     Fire1Item:  begin
  1892.                             GetLutResource(Fire1ID);
  1893.                             ColorTable := Fire1;
  1894.                         end;
  1895.                     Fire2Item:  begin
  1896.                             GetLutResource(Fire2ID);
  1897.                             ColorTable := Fire2;
  1898.                         end;
  1899.                     IceItem:  begin
  1900.                             GetLutResource(IceID);
  1901.                             ColorTable := Ice;
  1902.                         end;
  1903.                     GraysItem:  begin
  1904.                             GetLutResource(GraysID);
  1905.                             ColorTable := Grays;
  1906.                         end;
  1907.                     SpectrumItem: 
  1908.                         if ControlKeyDown and OptionKeyDown and ShiftKeyDown then
  1909.                             SaveLutResource
  1910.                         else begin
  1911.                                 MakeSpectrum;
  1912.                                 ColorTable := Spectrum;
  1913.                             end;
  1914.                 end; {case}
  1915.                 LutMode := Pseudocolor;
  1916.                 if update then begin
  1917.                         UpdateLUT;
  1918.                         UpdateMap;
  1919.                     end;
  1920.             end;
  1921.     end;
  1922.  
  1923.  
  1924.     procedure SetNumberOfColors (n: integer);
  1925.         var
  1926.             i, r, g, b, index: integer;
  1927.             eIndex, inc, fraction: extended;
  1928.             SaveRed, SaveGreen, SaveBlue: LutArray;
  1929.     begin
  1930.         with info^ do begin
  1931.                 SaveRed := RedLUT;
  1932.                 SaveGreen := GreenLUT;
  1933.                 SaveBlue := BlueLUT;
  1934.                 eIndex := 0.0;
  1935.                 inc := (nColors - 1) / (n - 1);
  1936.                 for i := 0 to n - 1 do begin
  1937.                         index := trunc(eIndex);
  1938.                         if index >= (nColors - 1) then begin
  1939.                                 RedLUT[i] := SaveRed[index];
  1940.                                 GreenLUT[i] := SaveGreen[index];
  1941.                                 BlueLUT[i] := SaveBlue[index]
  1942.                             end
  1943.                         else begin
  1944.                                 fraction := eIndex - index;
  1945.                                 RedLUT[i] := round(SaveRed[index] * (1.0 - fraction) + SaveRed[index + 1] * fraction);
  1946.                                 GreenLUT[i] := round(SaveGreen[index] * (1.0 - fraction) + SaveGreen[index + 1] * fraction);
  1947.                                 BlueLUT[i] := round(SaveBlue[index] * (1.0 - fraction) + SaveBlue[index + 1] * fraction);
  1948.                             end;
  1949.                         eIndex := eIndex + inc;
  1950.                     end;
  1951.                 nColors := n;
  1952.                 LutMode := PseudoColor;
  1953.                 ColorTable := CustomTable;
  1954.                 UpdateLUT;
  1955.                 UpdateMap;
  1956.             end;
  1957.     end;
  1958.  
  1959.  
  1960.     procedure SetNumberOfExtraColors;
  1961.         var
  1962.             n: integer;
  1963.             Canceled: boolean;
  1964.     begin
  1965.         n := GetInt('Number of Extra Colors(0..6):', nExtraColors, Canceled);
  1966.         if (n <= 6) and (n >= 0) and not Canceled then begin
  1967.                 nExtraColors := n;
  1968.                 RedrawLUTWindow;
  1969.                 SelectWindow(LUTWindow);
  1970.                 if info <> NoInfo then
  1971.                     SelectWindow(info^.wptr);
  1972.             end
  1973.         else if not Canceled then
  1974.             beep;
  1975.     end;
  1976.  
  1977.  
  1978.     procedure DoLutOptions;
  1979.         const
  1980.             nColorsID = 7;
  1981.             nExtraColorsID = 8;
  1982.             InvertID = 9;
  1983.         var
  1984.             mylog: DialogPtr;
  1985.             item, i, n, nExtra: integer;
  1986.             InvertLut: boolean;
  1987.     begin
  1988.         with info^ do begin
  1989.                 InitCursor;
  1990.                 mylog := GetNewDialog(210, nil, pointer(-1));
  1991.                 n := nColors;
  1992.                 SetDNum(MyLog, nColorsID, n);
  1993.                 nExtra := nExtraColors;
  1994.                 SetDNum(MyLog, nExtraColorsID, nExtra);
  1995.                 InvertLut := false;
  1996.                 SetDlogItem(mylog, InvertID, ord(InvertLut));
  1997.                 repeat
  1998.                     ModalDialog(nil, item);
  1999.                     if item = nColorsID then
  2000.                         n := GetDNum(MyLog, nColorsID);
  2001.                     if item = nExtraColorsID then
  2002.                         nExtra := GetDNum(MyLog, nExtraColorsID);
  2003.                     if item = InvertID then begin
  2004.                             InvertLut := not InvertLut;
  2005.                             SetDlogItem(mylog, InvertID, ord(InvertLut));
  2006.                         end;
  2007.                 until (item = ok) or (item = cancel);
  2008.                 DisposeDialog(mylog);
  2009.                 if item = cancel then
  2010.                     exit(DoLutOptions);
  2011.                 DisableDensitySlice;
  2012.                 SetupLutUndo;
  2013.                 if n < 1 then
  2014.                     n := 1;
  2015.                 if n > 256 then
  2016.                     n := 256;
  2017.                 if n <> nColors then
  2018.                     SetNumberOfColors(n);
  2019.                 if (nExtra <> nExtraColors) and (nExtra >= 0) and (nExtra <= 6) then begin
  2020.                         nExtraColors := nExtra;
  2021.                         RedrawLUTWindow;
  2022.                         SelectWindow(LUTWindow);
  2023.                         if info <> NoInfo then
  2024.                             SelectWindow(info^.wptr);
  2025.                     end;
  2026.                 if InvertLut then begin
  2027.                         InvertPalette;
  2028.                         UpdateLut;
  2029.                         if ScreenDepth <> 8 then
  2030.                             DrawLUT;
  2031.                     end;
  2032.             end; {with info}
  2033.     end;
  2034.  
  2035.  
  2036.     function SetupMask: boolean;
  2037. {Creates a mask in the undo buffer for operating}
  2038. {on non-rectangular selections .}
  2039.         var
  2040.             tPort: GrafPtr;
  2041.             SaveInfo: InfoPtr;
  2042.             SaveGDevice: GDHandle;
  2043.     begin
  2044.         if NoUndo then begin
  2045.                 SetupMask := false;
  2046.                 exit(SetupMask)
  2047.             end;
  2048.         SetupUndoInfoRec;
  2049.         SaveInfo := Info;
  2050.         Info := UndoInfo;
  2051.         SaveGDevice := GetGDevice;
  2052.         SetGDevice(osGDevice);
  2053.         GetPort(tPort);
  2054.         with Info^ do begin
  2055.                 SetPort(GrafPtr(osPort));
  2056.                 pmForeColor(BlackIndex);
  2057.                 pmBackColor(WhiteIndex);
  2058.                 PenNormal;
  2059.                 EraseRect(RoiRect);
  2060.                 PaintRgn(roiRgn);
  2061.             end;
  2062.         SetPort(tPort);
  2063.         SetGDevice(SaveGDevice);
  2064.         Info := SaveInfo;
  2065.         SetupMask := true;
  2066.     end;
  2067.  
  2068.     procedure ApplyTableToLine (data: ptr; var table: LookupTable; width: LongInt);
  2069. {$IFC PowerPC}
  2070.     var
  2071.         line: LinePtr;
  2072.         i: integer;
  2073.     begin
  2074.         line := LinePtr(data);
  2075.         for i := 0 to width - 1 do
  2076.             Line^[i] := table[band(Line^[i],255)];
  2077.     end;
  2078. {$ELSEC}
  2079.  
  2080. {a0 = data}
  2081. {a1 = lookup table}
  2082. {d0 = width }
  2083. {d1 = pixel value}
  2084. inline
  2085.     $4E56, $0000, {  link a6,#0}
  2086.     $48E7, $C0C0, {  movem.l a0-a1/d0-d1,-(sp)}
  2087.     $206E, $000C, {  move.l 12(a6),a0}
  2088.     $226E, $0008, {  move.l 8(a6),a1}
  2089.     $202E, $0004, {  move.l 4(a6),d0}
  2090.     $5380,       {  subq.l #1,d0}
  2091.     $4281,       {  clr.l d1}
  2092.     $1210,       {L move.b (a0),d1}
  2093.     $10F1, $1000, {  move.b 0(a1,d1.w),(a0)+}
  2094.     $51C8, $FFF8, {  dbra d0,L}
  2095.     $4CDF, $0303, {  movem.l (sp)+,a0-a1/d0-d1}
  2096.     $4E5E,       {  unlk a6}
  2097.     $DEFC, $000C; {  add.w #12,sp}
  2098. {$ENDC}
  2099.  
  2100.  
  2101. procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  2102.     var
  2103.         aLine, MaskLine: LineType;
  2104.         i: integer;
  2105.         SaveInfo: InfoPtr;
  2106. begin
  2107.     if count > MaxLine then
  2108.         count := MaxLine;
  2109.     GetLine(h, v, count, aline);
  2110.     SaveInfo := Info;
  2111.     Info := UndoInfo;
  2112.     GetLine(h, v, count, MaskLine);
  2113.     for i := 0 to count - 1 do
  2114.         if MaskLine[i] = BlackIndex then
  2115.             aLine[i] := line[i];
  2116.     info := SaveInfo;
  2117.     PutLine(h, v, count, aLine);
  2118. end;
  2119.  
  2120.  
  2121. procedure ApplyTable(var table: LookupTable);
  2122.     var
  2123.         width, NumberOfLines, i, hloc, vloc: integer;
  2124.         offset: LongInt;
  2125.         p: ptr;
  2126.         UseMask: boolean;
  2127.         TempLine: LineType;
  2128.         AutoSelectAll: boolean;
  2129. begin
  2130.     if NotInBounds then
  2131.         exit(ApplyTable);
  2132.     AutoSelectAll := not Info^.RoiShowing;
  2133.     if AutoSelectAll then
  2134.         SelectAll(false);
  2135.     if TooWide then
  2136.         exit(ApplyTable);
  2137.     ShowWatch;
  2138.     with info^.RoiRect, info^ do begin
  2139.             if RoiType <> RectRoi then
  2140.                 UseMask := SetupMask
  2141.             else
  2142.                 UseMask := false;
  2143.             SetupUndoFromClip;
  2144.             WhatToUndo := UndoTransform;
  2145.             offset := top * BytesPerRow + left;
  2146.             if UseMask then
  2147.                 p := @TempLine
  2148.             else
  2149.                 p := ptr(ord4(PicBaseAddr) + offset);
  2150.             width := right - left;
  2151.             NumberOfLines := bottom - top;
  2152.             hloc := left;
  2153.             vloc := top;
  2154.         end;
  2155.     if width > 0 then
  2156.         for i := 1 to NumberOfLines do
  2157.             if UseMask then begin
  2158.                     GetLine(hloc, vloc, width, TempLine);
  2159.                     ApplyTableToLine(p, table, width);
  2160.                     PutLineUsingMask(hloc, vloc, width, TempLine);
  2161.                     vloc := vloc + 1
  2162.                 end
  2163.             else begin
  2164.                     ApplyTableToLine(p, table, width);
  2165.                     p := ptr(ord4(p) + info^.BytesPerRow);
  2166.                 end;
  2167.     with info^ do begin
  2168.             UpdateScreen(RoiRect);
  2169.             Info^.changes := true;
  2170.         end;
  2171.     SetupRoiRect;
  2172.     if AutoSelectAll then
  2173.         KillRoi;
  2174. end;
  2175.  
  2176.  
  2177. procedure FixColors;
  2178.     {Because NIH Image always sets LUT entries 0 and 255 to white and black respectively we need to map}
  2179.     {pixels with values of 0 or 255 to the nearest matching color in the other 254  LUT entries.}
  2180.     var
  2181.         i, match0, match255: integer;
  2182.         table: LookupTable;
  2183.  
  2184.     procedure BestMatch (index1: integer; var match: integer);
  2185.         var
  2186.             i, index2: integer;
  2187.             rdiff, gdiff, bdiff, r1, g1, b1: LongInt;
  2188.             diff, mindiff: extended;
  2189.     begin
  2190.         match := index1;
  2191.         mindiff := 10e10;
  2192.         if index1 = 0 then
  2193.             index2 := 1
  2194.         else
  2195.             index2 := 254;
  2196.         with info^ do begin
  2197.             r1:=band(bsr(cTable[index1].rgb.red, 8),255);
  2198.             g1:=band(bsr(cTable[index1].rgb.green, 8),255);
  2199.             b1:=band(bsr(cTable[index1].rgb.blue, 8),255);
  2200.             for i := 1 to 254 do begin
  2201.                     rdiff := r1 - band(bsr(cTable[index2].rgb.red, 8),255);
  2202.                     gdiff := g1 - band(bsr(cTable[index2].rgb.green, 8),255);
  2203.                     bdiff := b1 - band(bsr(cTable[index2].rgb.blue, 8),255);
  2204.                     diff := sqrt(sqr(rdiff) + sqr(gdiff) + sqr(bdiff));
  2205.                     if diff < mindiff then begin
  2206.                             match := index2;
  2207.                             mindiff := diff;
  2208.                         end;
  2209.                     if index1 = 0 then
  2210.                         index2 := index2 + 1
  2211.                     else
  2212.                         index2 := index2 - 1;
  2213.                 end; {for}
  2214.         end; {with}
  2215.     end;
  2216.  
  2217. begin
  2218.     BestMatch(0, match0);
  2219.     BestMatch(255, match255);
  2220.     table[0] := match0;
  2221.     for i := 1 to 254 do
  2222.         table[i] := i;
  2223.     table[255] := match255;
  2224.     ApplyTable(table);
  2225. end;
  2226.  
  2227.  
  2228. end.